
package com.hulk.ratel.web.interceptor;

import com.baomidou.mybatisplus.toolkit.IdWorker;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.hulk.common.util.DateUtil;
import com.hulk.common.util.JsonMapper;
import com.hulk.ratel.common.constant.enums.BussErrCode;
import com.hulk.ratel.common.exception.BaseRteException;
import com.hulk.ratel.common.exception.SecurityRteException;
import com.hulk.ratel.common.exception.WebRteException;
import com.hulk.ratel.common.security.ProvideSecurityWarper;
import com.hulk.ratel.manage.commoncache.PartnerKeyCache;
import com.hulk.ratel.manage.commoncache.SecurityPartnerCache;
import com.hulk.ratel.persistence.entity.TPartnerKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.List;
import java.util.Optional;

/**
 * @author hulk
 * @version Create on: 2017年4月12日 下午2:29:11 Class description
 * @E-mail:29572320@qq.com
 */

@Slf4j
@Order(6)
public class SecurityInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private SecurityPartnerCache securityPartnerCache;

    @Autowired
    private PartnerKeyCache partnerKeyCache;

    private static JsonMapper json = JsonMapper.JSON_NON_DEFAULT_MAPPER;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String workId = String.valueOf(IdWorker.getId());
        String intCutDate = DateUtil.getDateyyyyMMdd();
        String URI = request.getRequestURI().trim();

        List<String> array = Splitter.on('/').trimResults().omitEmptyStrings().splitToList(URI);
        String txnCodeURISuffix = array.get(array.size() - 1);

        if (URI.contains("heartbeat") || URI.contains("keepalive") ) {
            return super.preHandle(request, response, handler);
        }
        

        String encryptData = request.getParameter("encryptData");
        if (Strings.isNullOrEmpty(encryptData)) {
            throw new WebRteException(workId, BussErrCode.E_100001.getErrCode(), "encryptData:" + BussErrCode.E_100001.getErrDesc());
        }
        String encryptKey = request.getParameter("encryptKey");
        if (Strings.isNullOrEmpty(encryptKey)) {
            throw new WebRteException(workId, BussErrCode.E_100001.getErrCode(), "encryptKey:" + BussErrCode.E_100001.getErrDesc());
        }
        String signData = request.getParameter("signData");
        if (Strings.isNullOrEmpty(signData)) {
            throw new WebRteException(workId, BussErrCode.E_100001.getErrCode(), "signData:" + BussErrCode.E_100001.getErrDesc());
        }
        String traceId = request.getParameter("traceId");
        if (Strings.isNullOrEmpty(traceId)) {
            throw new WebRteException(workId, BussErrCode.E_100001.getErrCode(), "traceId:" + BussErrCode.E_100001.getErrDesc());
        }
        String partnerNo = request.getParameter("partnerNo");
        if (Strings.isNullOrEmpty(partnerNo)) {
            throw new WebRteException(workId, BussErrCode.E_100001.getErrCode(), "partnerNo:" + BussErrCode.E_100001.getErrDesc());
        }

        log.info("接受合作者报文内容: URI:{},txnCode:{}, encryptData:{},encryptKey:{},signData:{},partnerNo:{},traceId:{},生成平台号：workId:{}",
                new Object[]{URI, txnCodeURISuffix, encryptData, encryptKey, signData, partnerNo, traceId, workId});
        request.setAttribute("workId", workId);
        request.setAttribute("txnCode", txnCodeURISuffix);
        request.setAttribute("partnerNo", partnerNo);
        request.setAttribute("traceId", traceId);
        request.setAttribute("intCutDate", intCutDate);

        String plainText;
        String partnerAESKey;
        boolean flag;
        try {
            //合作方密钥查询
            TPartnerKey partnerKey = Optional.ofNullable(partnerKeyCache.findPartnerKey(workId, partnerNo))
                    .orElseThrow(()->new SecurityRteException(workId,BussErrCode.E_100002));

            // 获取商户密钥信息

            String partnerPublicKeyStr = partnerKey.getPartnerPublickey();
            String platformPrivateKeyStr = partnerKey.getPlatformPrivatekey();
            //String partnerPublicKeySuffix = partnerPublicKeyStr.substring(partnerPublicKeyStr.lastIndexOf(".") + 1);
            String partnerPublicKeySuffix = partnerKey.getPartnerPublickeySuffix();
            //String platformPrivateKeySuffix = platformPrivateKeyStr.substring(platformPrivateKeyStr.lastIndexOf(".") + 1);
            String platformPrivateKeySuffix =partnerKey.getPlatformPrivatekeySuffix();
            String keypathType =  partnerKey.getKeypathType();
            PublicKey publicKeyPartner = Optional.ofNullable(securityPartnerCache.findPublicKey(partnerNo, partnerPublicKeyStr, partnerPublicKeySuffix, keypathType))
                    .orElseThrow(() -> new SecurityRteException(workId, BussErrCode.E_100010));

            PrivateKey privateKeyPlatform = Optional.ofNullable(securityPartnerCache.findPrivateKey(partnerNo,platformPrivateKeyStr,platformPrivateKeySuffix, keypathType))
                    .orElseThrow(() -> new SecurityRteException(workId, BussErrCode.E_100020));

            partnerAESKey = ProvideSecurityWarper.getPartnerAESKeyByPlatformPrivateKey(encryptKey,
                    privateKeyPlatform);
            plainText = ProvideSecurityWarper.getPlainTextByAESKey(encryptData, partnerAESKey);
            //log.info("plainText:{}", plainText);
            flag = ProvideSecurityWarper.checkSignB64PlainTextByPartnerPublicKey(plainText, signData,
                    publicKeyPartner);
        } catch (BaseRteException be) {
            throw new SecurityRteException(workId, be.getErrorCode(), be.getErrorMessage());

        } catch (Exception e) {
            throw new SecurityRteException(workId, BussErrCode.E_100004);
        }
        if (Strings.isNullOrEmpty(partnerAESKey) | (16 != partnerAESKey.trim().length())) {
            throw new SecurityRteException(workId, BussErrCode.E_100015);
        }
        //plainText = plainText.replace("&quot;", "\"");
        plainText = StringEscapeUtils.unescapeHtml4(plainText);
        log.info("plainText unescapeHtml4:{}", plainText);
        JsonNode node = json.treeFromJson(plainText);
        node = node.get("head");
        String traceIdHead = node.get("traceId").textValue().trim();
        String partnerNoHead = node.get("partnerNo").textValue().trim();
        String txnCodeHead = node.get("txnCode").textValue().trim();
        if (Strings.isNullOrEmpty(traceIdHead) | Strings.isNullOrEmpty(partnerNoHead) | Strings.isNullOrEmpty(txnCodeHead)) {
            throw new SecurityRteException(workId, BussErrCode.E_100001);
        }
        if (!Objects.equal(traceIdHead, traceId)) {
            throw new SecurityRteException(workId, BussErrCode.E_100001.getErrCode(), "traceId和traceIdHead不相等");
        }
        if (!Objects.equal(partnerNoHead, partnerNo)) {
            throw new SecurityRteException(workId, BussErrCode.E_100002);
        }

//        if (!Objects.equal(txnCodeHead, txnCodeURISuffix)) {
//            throw new WebRteException(workId, BussErrCode.E_100005.getErrCode(), BussErrCode.E_100005.getErrDesc());
//        }

        if (!flag) {
            throw new SecurityRteException(workId, BussErrCode.E_100003);
        }

        log.info("signflag:{},traceId:{},workId:{}", flag, traceId, workId);

        request.setAttribute("plainText", plainText);
        request.setAttribute("partnerAESKey", partnerAESKey);
        request.setAttribute("requestHead", json.treeFromJson(plainText).path("head").toString());

        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        log.debug("CommunicationSecurityInterceptor.postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        log.debug("CommunicationSecurityInterceptor.afterCompletion", ex);
    }
}
